﻿/*----------------------------------------------------------------
// 公司名称：公司名称
//
// 产品名称：Gaf
//
// 创 建 人：netcasewqs
// 创建日期：2022/3/4
// 邮    箱：netcasewqs@qq.com
//
// Copyright (C) 2022 Gaf，保留所有权利。
//
//----------------------------------------------------------------*/

namespace Gaf;

/// <summary>
/// Framework 静态工厂类
/// </summary>
public static class GafManager
{
    private static readonly object Mutex = new();

    private static IGaf _gaf = null!;

    /// <summary>
    /// 当前的Gaf实例
    /// </summary>
    public static IGaf Current
    {
        get
        {
            Validate();

            return _gaf;
        }
    }

    /// <summary>
    /// 初始化Gaf 框架
    /// </summary>
    /// <param name="options"></param>
    public static void Initialize(GafOptions? options = null)
    {
        if (_gaf == null) Create(options);
    }

    /// <summary>
    /// 创建一个新的Gaf实例对象
    /// </summary>
    /// <param name="options"></param>
    public static IGaf Create(GafOptions? options = null)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        Directory.SetCurrentDirectory(AppContext.BaseDirectory);

        options ??= GetFrameworkConfig();

        if (options.EnableRedundantDllFileCheck) // 冗余dll 检查
            RedundantDllFileChecker.RedundantCheck();

        if (Log.Enabled)
        {
            Log.TraceFile = Log.TraceFile ?? "gaf.log.txt";
            //Trace.Listeners.Add(new TextWriterTraceListener(Log.TraceFile));
        }

        lock (Mutex)
        {
            Log.Info("Create Framework...");
            _gaf = new GafImpl(options);

            return _gaf;
        }
    }

    private static void Validate()
    {
        if (_gaf == null)
        {
            string message = $"Gaf 还没有初始化，请首先调用{typeof(GafManager).Name}.{nameof(Create)}() 方法!";
            throw new InvalidOperationException(message);
        }
    }

    private static GafOptions GetFrameworkConfig()
    {
        var frameworkConfigFile = Path.Combine(AppContext.BaseDirectory, Constants.GafFileName);

        GafOptions description = null!;
        if (!File.Exists(frameworkConfigFile))
            description = new GafOptions();
        else
        {
            String errorMessage = null!; ;
            var result = Serialize(frameworkConfigFile,
                ex => errorMessage = $"解析{Constants.GafFileName}文件失败，错误信息:{ex.Message}") ?? throw new AddinException(AddinExceptionType.FrameworkInitError, errorMessage);
            description = result;
        }

        if (description.PackageFormat == AddinPackageFormat.Lite)
            description.AddinsDirectory = AppContext.BaseDirectory;
        else
            description.AddinsDirectory = Path.Combine(AppContext.BaseDirectory, description.AddinsDirectory);

        static GafOptions? Serialize(string frameworkConfigFile, Action<Exception> parseException)
        {
            if (!File.Exists(frameworkConfigFile))
            {
                parseException(new Exception($"{frameworkConfigFile} 不存在。"));

                return default;
            }

            try
            {
                var options = new GafOptions();

                var lines = File.ReadAllLines(frameworkConfigFile);

                foreach (var line in lines)
                {
                    if (string.IsNullOrEmpty(line)) continue;

                    if (line.StartsWith(";") || line.StartsWith("#"))
                    {
                        continue;
                    }

                    var keyValue = line.Split(new[] { "=" }, 2, StringSplitOptions.RemoveEmptyEntries);
                    if (keyValue.Length != 2) continue;

                    var key = keyValue[0];
                    var value = keyValue[1];
                    if (string.IsNullOrEmpty(value)) continue;
                    if (string.IsNullOrEmpty(key)) continue;

                    key = key.Trim();
                    value = value.Trim();

                    if (string.Equals(key, nameof(GafOptions.AddinsDirectory), StringComparison.OrdinalIgnoreCase))
                        options.AddinsDirectory = value;
                    else if (string.Equals(key, nameof(GafOptions.PackageSuffixName), StringComparison.OrdinalIgnoreCase))
                        options.PackageSuffixName = value;
                    else if (string.Equals(key, nameof(GafOptions.PackageFormat), StringComparison.OrdinalIgnoreCase))
                    {
                        if (Enum.TryParse<AddinPackageFormat>(value, out var format))
                        {
                            options.PackageFormat = format;
                        }
                        else
                        {
                            if (int.TryParse(value, out var i))
                                options.PackageFormat = (AddinPackageFormat)i;
                            else
                                options.PackageFormat = AddinPackageFormat.Lite | AddinPackageFormat.Directory;
                        }
                    }
                    else if (string.Equals(key, nameof(GafOptions.ManagedLibsDirectory), StringComparison.OrdinalIgnoreCase))
                        options.ManagedLibsDirectory = value;
                    else if (string.Equals(key, nameof(GafOptions.UnmanagedLibsDirectory), StringComparison.OrdinalIgnoreCase))
                        options.UnmanagedLibsDirectory = value;
                    else if (string.Equals(key, nameof(GafOptions.MaxStartLevel), StringComparison.OrdinalIgnoreCase))
                    {
                        if (uint.TryParse(value, out var level))
                            options.MaxStartLevel = level;
                    }
                    else if (string.Equals(key, nameof(GafOptions.DisableAddins), StringComparison.OrdinalIgnoreCase))
                        options.DisableAddins = value.Split(new char[] { ';', ',', '，', '；' }, StringSplitOptions.RemoveEmptyEntries);
                    else if (string.Equals(key, nameof(GafOptions.EnableRedundantDllFileCheck), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.EnableRedundantDllFileCheck = enabled;
                    }
                    else if (string.Equals(key, nameof(GafOptions.AutoDeleteUncompressDirectory), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.AutoDeleteUncompressDirectory = enabled;
                    }
                    else if (string.Equals(key, nameof(GafOptions.AutoExitOnStartAddinError), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.AutoExitOnStartAddinError = enabled;
                    }
                    else if (string.Equals(key, nameof(GafOptions.AddinIsolation), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.AddinIsolation = enabled;
                    }
                    else if (string.Equals(key, nameof(GafOptions.AddinCanUninstall), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.AddinCanUninstall = enabled;
                    }
                   
                    else if (string.Equals(key, nameof(GafOptions.AddinAssemblyLoadMode), StringComparison.OrdinalIgnoreCase))
                    {
                        if (Enum.TryParse<AddinAssemblyLoadMode>(value, out var format))
                        {
                            options.AddinAssemblyLoadMode = format;
                        }
                        else
                        {
                            if (value == "0") options.AddinAssemblyLoadMode = AddinAssemblyLoadMode.LoadFromStream;
                            else if (value == "1") options.AddinAssemblyLoadMode = AddinAssemblyLoadMode.LoadFromAssemblyPath;
                        }
                    }
                    else if (string.Equals(key, nameof(GafOptions.TraceFile), StringComparison.OrdinalIgnoreCase))
                    {
                        options.TraceFile = Log.TraceFile =  value;
                    }
                    else if (string.Equals(key, nameof(GafOptions.Trace), StringComparison.OrdinalIgnoreCase))
                    {
                        if (bool.TryParse(value, out var enabled))
                            options.Trace = Log.Enabled =  enabled;
                    }
                    else if (string.Equals(key, nameof(TraceLevel), StringComparison.OrdinalIgnoreCase))
                    {
                        if (Enum.TryParse<TraceLevel>(value, out var logLevel))
                        {
                            Log.Level = options.TraceLevel = logLevel;
                        }
                    }
                }

                return options;
            }
            catch (Exception ex)
            {
                parseException(ex);
                return default;
            }
        }

        return description;
    }
}